/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * $Revision: 9818 $
 * $Id: startherepage.cpp 9818 2014-06-20 05:26:04Z mortenmacfly $
 * $HeadURL: http://svn.code.sf.net/p/codeblocks/code/branches/release-17.xx/src/src/startherepage.cpp $
 */

#include <sdk.h>

#ifndef CB_PRECOMP

#include <wx/dataobj.h>
#include <wx/intl.h>
#include <wx/utils.h>
#include <wx/sizer.h>
#include <wx/settings.h>

#include <manager.h>
#include <logmanager.h>
#include <projectmanager.h>
#include <templatemanager.h>
#include <pluginmanager.h>
#include <editormanager.h>
#include <configmanager.h>

#endif

#include "startherepage.h"
#include "main.h"
#include "appglobals.h"
#include "cbcolourmanager.h"
#include "recentitemslist.h"

#include <wx/clipbrd.h>
#include <wx/docview.h>
#include <wx/wxhtml.h>

const wxString g_StartHereTitle = wxT("从这里开始");
int idWin = wxNewId();

class MyHtmlWin : public wxHtmlWindow {
public:
    MyHtmlWin(StartHerePage *parent, int id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxHW_SCROLLBAR_AUTO)
            : wxHtmlWindow(parent, id, pos, size, style),
              m_pOwner(parent) {
    }

    void OnLinkClicked(const wxHtmlLinkInfo &link) {
        if (m_pOwner) {
            if (!m_pOwner->LinkClicked(link))
                wxLaunchDefaultBrowser(link.GetHref());
        }
    }

private:
    StartHerePage *m_pOwner;
};

BEGIN_EVENT_TABLE(StartHerePage, EditorBase)
END_EVENT_TABLE()

namespace {

    wxString wrapText(const wxString &text, const wxString &textColour) {
        return wxT("<font color=\"") + textColour + wxT("\">") + text + wxT("</font>");
    }

    void ReplaceRecentProjectFiles(wxString &buf, const wxFileHistory &projects, const wxFileHistory &files,
                                   const wxString &linkColour, const wxString &textColour) {
        /*替换历史变量*/
        wxString links;

        links << _T("<table>\n<tr><td colspan=\"2\"><b>");
        links << wrapText(wxT("最近打开项目"), textColour);
        links << _T("</b></td></tr>\n");
        if (projects.GetCount()) {
            for (size_t i = 0; i < projects.GetCount(); ++i) {
                links << _T("<tr><td width=\"50\"><img alt=\"\" width=\"20\" src=\"blank.png\" />");
                links << wxString::Format(_T("<a href=\"CB_CMD_DELETE_HISTORY_PROJECT_%lu\"><img alt=\"\" src=\"trash_16x16.png\" /></a>"),
                                          static_cast<unsigned long>(i + 1));
                links << _T("<img alt=\"\"  width=\"10\" src=\"blank.png\" /></td><td width=\"10\">");
                links << _T("<a href=\"CB_CMD_OPEN_HISTORY_PROJECT_") << (i + 1) << _T("\">")
                      << _T("<font color=\"") << linkColour << _T("\">") << projects.GetHistoryFile(i)
                      << _T("</font></a>");
                links << _T("</td></tr>\n");
            }
        } else {
            links << _T("<tr><td style=\"width:2em;\"></td><td>&nbsp;&nbsp;&nbsp;&nbsp;");
            links << wrapText(wxT("最近没有打开过项目"), textColour);
            links << _T("</td></tr>\n");
        }

        links << _T("</table>\n<table>\n<tr><td colspan=\"2\"><b>");
        links << wrapText(wxT("最近打开文件"), textColour);
        links << _T("</b></td></tr>\n");
        if (files.GetCount()) {
            for (size_t i = 0; i < files.GetCount(); ++i) {
                links << _T("<tr><td width=\"50\"><img alt=\"\" width=\"20\" src=\"blank.png\" />");
                links << wxString::Format(wxT("<a href=\"CB_CMD_DELETE_HISTORY_FILE_%lu\"><img alt=\"\" src=\"trash_16x16.png\" /></a>"),
                                          static_cast<unsigned long>(i + 1));
                links << _T("<img alt=\"\"  width=\"10\" src=\"blank.png\" /></td><td width=\"10\">");
                links << _T("<a href=\"CB_CMD_OPEN_HISTORY_FILE_") << (i + 1) << _T("\">")
                      << _T("<font color=\"") << linkColour << _T("\">") << files.GetHistoryFile(i) << _T("</font></a>");
                links << _T("</td></tr>\n");
            }
        } else {
            links << _T("<tr><td style=\"width:2em;\"></td><td>&nbsp;&nbsp;&nbsp;&nbsp;");
            links << wrapText(wxT("没有最近打开文件"), textColour);
            links << _T("</td></tr>\n");
        }

        links << _T("</table>\n");

        /*更新页面*/
        buf.Replace(_T("CB_VAR_RECENT_FILES_AND_PROJECTS"), links);
        buf.Replace(_T("CB_TXT_NEW_PROJECT"), wxT("创建一个新项目"));
        buf.Replace(_T("CB_TXT_OPEN_PROJECT"), wxT("打开一个存在的项目"));
        buf.Replace(_T("CB_TXT_VISIT_FORUMS"), wxT("访问Code::Blocks论坛"));
        buf.Replace(_T("CB_TXT_BUG_FEATURE"), wxT("报告错误或请求新功能"));
        buf.Replace(_T("CB_TXT_TIP_OF_THE_DAY"), wxT("最新消息"));
    }

}

StartHerePage::StartHerePage(wxEvtHandler *owner, const RecentItemsList &projects,
                             const RecentItemsList &files, wxWindow *parent)
        : EditorBase(parent, g_StartHereTitle),
          m_pOwner(owner),
          m_projects(projects),
          m_files(files) {
    /*构造函数*/
    RegisterColours();
    wxBoxSizer *bs = new wxBoxSizer(wxVERTICAL);
    wxString resPath = ConfigManager::ReadDataPath();

    /*避免gtk-critical,因为大小小于-1(可以在wxAuiNotebook/cbAuiNotebook中发生)*/
    wxSize size = GetSize();
    size.x = std::max(size.x, -1);
    size.y = std::max(size.y, -1);
    m_pWin = new MyHtmlWin(this, idWin, wxPoint(0, 0), size);

    /*根据系统默认字体大小设置默认字体大小*/
    /*注意(mandrav#1#):wxHtmlWindow::SetFonts()上的wxWidgets文档说明sizes数组接受从-2到+4的值.我的测试(至少在linux下)表明它实际期望的是实点大小.*/

    wxFont systemFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
    int sizes[7] = {};
    for (int i = 0; i < 7; ++i) {
        sizes[i] = systemFont.GetPointSize();
    }

    m_pWin->SetFonts(wxEmptyString, wxEmptyString, &sizes[0]);


    /*必须以这种方式加载页面,因为如果我们不这样做,图像就找不到...*/
    m_pWin->LoadPage(resPath + _T("/start_here.zip#zip:start_here.html"));

    /*另一种读取文件的方法,以便我们可以执行一些搜索并替换默认起始页中引用的C::B图像,现在可以找到,因为我们在上面使用了LoadPage()...*/

    wxString buf;
    wxFileSystem *fs = new wxFileSystem;
    wxFSFile *f = fs->OpenFile(resPath + _T("/start_here.zip#zip:start_here.html"));
    if (f) {
        wxInputStream *is = f->GetStream();
        char tmp[1024] = {};
        while (!is->Eof() && is->CanRead()) {
            memset(tmp, 0, sizeof(tmp));
            is->Read(tmp, sizeof(tmp) - 1);
            buf << cbC2U((const char *) tmp);
        }
        delete f;
    } else
        buf = wxT("<html><body><h1>欢迎使用Code::Blocks!</h1><br>默认起始页似乎丢失...</body></html>");
    delete fs;

#if defined(_LP64) || defined(_WIN64)
    const int bit_type = 64;
#else
    const int bit_type = 32;
#endif

#ifdef __GNUC__
    revInfo.Printf(wxT("%s (%s)   gcc %d.%d.%d %s/%s - %d 位"),
                   appglobals::AppActualVersionVerb.wx_str(), ConfigManager::GetSvnDate().wx_str(),
                   __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, appglobals::AppPlatform.wx_str(), appglobals::AppWXAnsiUnicode.wx_str(), bit_type);
#else
    revInfo.Printf(_T("%s (%s)   %s/%s"),
                    appglobals::AppActualVersionVerb.c_str(), ConfigManager::GetSvnDate().c_str(),
                    appglobals::AppPlatform.c_str(), appglobals::AppWXAnsiUnicode.c_str());
#endif

    /*执行变量替换*/
    buf.Replace(_T("CB_VAR_REVISION_INFO"), revInfo);
    buf.Replace(_T("CB_VAR_VERSION_VERB"), appglobals::AppActualVersionVerb);
    buf.Replace(_T("CB_VAR_VERSION"), appglobals::AppActualVersion);
    buf.Replace(_T("CB_SAFE_MODE"), PluginManager::GetSafeMode() ? wxT("安全模式") : wxT(""));

    /*保留一份原件副本以供重重载*/
    m_OriginalPageContent = buf;
    Reload();

    bs->Add(m_pWin, 1, wxEXPAND);
    SetSizer(bs);
    SetAutoLayout(true);
}

StartHerePage::~StartHerePage() {
    /*析构函数m_pWin->Destroy();*/
}

void StartHerePage::RegisterColours() {
    static bool inited = false;
    if (inited)
        return;
    inited = true;

    ColourManager *cm = Manager::Get()->GetColourManager();
    cm->RegisterColour(wxT("起始页面"), wxT("背景色"), wxT("start_here_background"), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
    cm->RegisterColour(wxT("起始页面"), wxT("超链接颜色"), wxT("start_here_link"), *wxBLUE);
    cm->RegisterColour(wxT("起始页面"), wxT("文本颜色"), wxT("start_here_text"), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
}

void StartHerePage::Reload() {
    /*每次历史记录变化都会被调用*/
    wxString buf = m_OriginalPageContent;

    ColourManager *cm = Manager::Get()->GetColourManager();
    const wxString &backgroundColour = cm->GetColour(wxT("start_here_background")).GetAsString(wxC2S_HTML_SYNTAX);
    const wxString &linkColour = cm->GetColour(wxT("start_here_link")).GetAsString(wxC2S_HTML_SYNTAX);
    const wxString &textColour = cm->GetColour(wxT("start_here_text")).GetAsString(wxC2S_HTML_SYNTAX);

    ReplaceRecentProjectFiles(buf, *m_projects.GetFileHistory(), *m_files.GetFileHistory(), linkColour, textColour);

    buf.Replace(wxT("CB_BODY_BGCOLOUR"), backgroundColour);
    buf.Replace(wxT("CB_LINK_COLOUR"), linkColour);
    buf.Replace(wxT("CB_TEXT_COLOUR"), textColour);

    int x, y;
    m_pWin->GetViewStart(&x, &y);
    m_pWin->SetPage(buf);
    m_pWin->Scroll(x, y);
}

bool StartHerePage::LinkClicked(const wxHtmlLinkInfo &link) {
    /*如果在载入某些内容,就停在这里*/
    if (Manager::Get()->GetProjectManager()->IsLoading()) { return true; }
    if (!m_pOwner) { return true; }

    wxString href = link.GetHref();
    if (href.StartsWith(_T("CB_CMD_"))) {
        wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, idStartHerePageLink);
        evt.SetString(link.GetHref());
        wxPostEvent(m_pOwner, evt);
        return true;
    }

    if (href.IsSameAs(_T("http://www.codeblocks.org/")) || href.StartsWith(_T("https://sourceforge.net/p/codeblocks/tickets"))) {
        wxTextDataObject *data = new wxTextDataObject(revInfo);
        if (wxTheClipboard->Open()) {
            wxTheClipboard->SetData(data);
            wxTheClipboard->Close();
        }
    }

    if (href.IsSameAs(_T("rev"))) {
        wxTextDataObject *data = new wxTextDataObject(revInfo);
        if (wxTheClipboard->Open()) {
            wxTheClipboard->SetData(data);
            wxTheClipboard->Close();
        }
        return true;
    }

    return false;
}
